package com.practice.security.rsa;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAKeyPairGenerator {

	private static final String PRIVATE_KEY_PATH = "./RSA/privateKey.bin";

	private static final String PUBLIC_KEY_PATH = "./RSA/publicKey.bin";

	private static final String PRIVATE_KEY_BASE64_PATH = "./RSA/privateKey.p8";

	private static final String PUBLIC_KEY_BASE64_PATH = "./RSA/publicKey.pem";

	private static final String RSA_ALGORITHM = "RSA";

	private static final int KEY_SIZE = 1024;

	public static void main(String[] args) throws IOException {

		KeyPair keyPair = generateKeyPair();
		if (keyPair == null) {
			return;
		}

		PrivateKey privateKey = keyPair.getPrivate();
		PublicKey publicKey = keyPair.getPublic();

		writePrivateKey(privateKey);
		writePublicKey(publicKey);
	}

	public static KeyPair generateKeyPair() {

		KeyPair keyPair = null;
		try {
			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
			keyPairGenerator.initialize(KEY_SIZE);
			keyPair = keyPairGenerator.generateKeyPair();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return keyPair;
	}

	public static void writePrivateKey(PrivateKey privateKey) throws IOException {

		Files.write(Paths.get(PRIVATE_KEY_PATH), privateKey.getEncoded());
		Files.write(Paths.get(PRIVATE_KEY_BASE64_PATH), Base64.getEncoder().encode(privateKey.getEncoded()));
	}

	public static PrivateKey readPrivateKey() throws IOException {

		byte[] privateKeyBytes = Files.readAllBytes(Paths.get(RSAKeyPairGenerator.PRIVATE_KEY_PATH));

		PrivateKey privateKey = null;
		try {
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
			KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
			privateKey = keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return privateKey;
	}

	public static void writePublicKey(PublicKey publicKey) throws IOException {

		Files.write(Paths.get(PUBLIC_KEY_PATH), publicKey.getEncoded());
		Files.write(Paths.get(PUBLIC_KEY_BASE64_PATH), Base64.getEncoder().encode(publicKey.getEncoded()));
	}

	public static PublicKey readPublicKey() throws IOException {

		byte[] publicKeyBytes = Files.readAllBytes(Paths.get(RSAKeyPairGenerator.PUBLIC_KEY_PATH));

		PublicKey publicKey = null;
		try {
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
			KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
			publicKey = keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
			e.printStackTrace();
		}
		return publicKey;
	}

}
